Skip to content

Add NullIf for reference types#6

Merged
Tyrrrz merged 9 commits intoprimefrom
copilot/add-nullif-to-reference-types
Apr 12, 2026
Merged

Add NullIf for reference types#6
Tyrrrz merged 9 commits intoprimefrom
copilot/add-nullif-to-reference-types

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 12, 2026

NullIf existed only for value types (where T : struct). Reference types had no equivalent.

Changes

  • FunctionalExtensions.cs — adds a second static class ReferenceTypeFunctionalExtensions in the same file containing NullIf<T>(Func<T, bool>) for where T : class, implemented using an extension block. A comment explains why it must live in a separate class: C# (CS0111) prohibits two generic methods with identical parameter types differing only in class vs struct constraints in the same class. The implementation uses Pipe to safely short-circuit on null receivers (value?.Pipe(v => !predicate(v) ? v : null)), so the predicate is never invoked when the receiver is null.
  • FunctionalExtensionsTests.cs — adds NullIf_ReferenceType_Test, including a null-receiver case that verifies the predicate is not invoked.

Usage

"hello".NullIf(v => v == "hello")  // null
"world".NullIf(v => v == "hello")  // "world"
((string)null!).NullIf(v => ...)   // null (predicate never called)

Agent-Logs-Url: https://github.com/Tyrrrz/PowerKit/sessions/d88377f7-cbd1-4cea-be4c-7a492da6a4a1

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Comment thread PowerKit/Extensions/ObjectExtensions.cs Outdated
… CS0111 comment

Agent-Logs-Url: https://github.com/Tyrrrz/PowerKit/sessions/45564995-2b08-4513-b4e1-40710df90b53

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
…cs; delete ObjectExtensions.cs

Agent-Logs-Url: https://github.com/Tyrrrz/PowerKit/sessions/bb377f2c-ed23-4c2f-baf7-63ea0c198192

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
/// <summary>
/// Returns <see langword="null" /> if the value matches the specified predicate; otherwise, returns the value.
/// </summary>
public static T? NullIf<T>(this T value, Func<T, bool> predicate)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use extension blocks @copilot

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in b3adbfeFunctionalExtensions2 now uses an extension<T>(T value) where T : class { ... } block.

@Tyrrrz Tyrrrz marked this pull request as ready for review April 12, 2026 13:23
Copilot AI requested a review from Tyrrrz April 12, 2026 13:23
Copilot AI review requested due to automatic review settings April 12, 2026 13:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a reference-type overload of NullIf to PowerKit’s functional extensions so NullIf can be used consistently for both struct and class values.

Changes:

  • Added NullIf<T>(Func<T, bool>) for where T : class via a new extensions class in FunctionalExtensions.cs
  • Added a unit test covering basic reference-type usage

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
PowerKit/Extensions/FunctionalExtensions.cs Introduces a reference-type NullIf extension (placed in a second static class due to constraint-based overload limitations).
PowerKit.Tests/FunctionalExtensionsTests.cs Adds a new test validating NullIf behavior on strings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread PowerKit/Extensions/FunctionalExtensions.cs Outdated
Comment on lines +54 to +56
/// Returns <see langword="null" /> if the value matches the specified predicate; otherwise, returns the value.
/// </summary>
public T? NullIf(Func<T, bool> predicate) => !predicate(value) ? value : null;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference types, this extension method can be invoked on a null receiver; in that case it will call predicate(value) with value == null, which can easily throw and makes null not behave as a no-op. Consider short-circuiting when value is null (return null without invoking the predicate) so the method is safe to use with nullable reference values.

Suggested change
/// Returns <see langword="null" /> if the value matches the specified predicate; otherwise, returns the value.
/// </summary>
public T? NullIf(Func<T, bool> predicate) => !predicate(value) ? value : null;
/// Returns <see langword="null" /> if the value is <see langword="null" /> or matches the specified predicate;
/// otherwise, returns the value.
/// </summary>
public T? NullIf(Func<T, bool> predicate) =>
value is null ? null : !predicate(value) ? value : null;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot implement this suggestions, but with the Pipe method

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1d874b6NullIf now uses value?.Pipe(v => !predicate(v) ? v : null), so a null receiver short-circuits without invoking the predicate. The test also covers this case.

Comment thread PowerKit.Tests/FunctionalExtensionsTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants